#pragma once
#include<unordered_map>
#include<sys/epoll.h>
#include"Epoller.hpp"
#include<functional>
#include"Socket.hpp"
#include<iostream>
#include"Comm.hpp"
#include <cerrno>
#include<memory>



class TcpServer;
class Connection;
static const int num=64;
const int defaultport=8888;
const static int g_buffer_size = 128;
using func_t = std::function<void(std::weak_ptr<Connection>)>;
using except_func = std::function<void(std::weak_ptr<Connection>)>;
uint32_t EVENT_IN = (EPOLLIN | EPOLLET);//要监听一个文件描述符的可读事件，并使用边缘触发模式。当数据到达文件描述符的接收缓冲区时，该事件将被触发.
uint32_t EVENT_OUT = (EPOLLOUT | EPOLLET);

class Connection
{
public:
    Connection(int sock)
    :_sock(sock)
    {

    }
    int SockFd() { return _sock; }
     void AppendInBuffer(const std::string &info)
    {
        _inbuffer += info;
    }
    void AppendOutBuffer(const std::string &info)
    {
        _outbuffer += info;
    }
     void SetWeakPtr(std::weak_ptr<TcpServer> tcp_server_ptr)
    {
        _tcp_server_ptr = tcp_server_ptr;
    }
     void SetHandler(func_t recv_cb, func_t send_cb, except_func except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }
    std::string &Inbuffer() // for debug
    {
        return _inbuffer;
    }
    std::string &OutBuffer()
    {
        return _outbuffer;
    }
     
public:
    func_t _recv_cb;
    func_t _send_cb;
    except_func _except_cb;

    // 添加一个回指指针
    std::weak_ptr<TcpServer> _tcp_server_ptr; // std::weak_ptr<> // bug??
    // std::shared_ptr<TcpServer> _tcp_server_ptr; // std::weak_ptr<>

    std::string _ip;
    uint16_t _port;
private:
    int _sock;
    std::string _inbuffer; // string 二进制流，vector
    std::string _outbuffer;

};

class TcpServer:public std::enable_shared_from_this<TcpServer>, public nocopy
{
public:
    TcpServer(std::uint16_t port=defaultport, func_t OnMessage)
    :_port(port)
    ,_OnMessage(OnMessage)
    ,_quit(true)
    ,_listensock_ptr(new Sock())
    ,_epoller_ptr(new Epoller())
    { 

    }
    void Init()
    {
         _listensock_ptr->Socket();
         SetNonBlockOrDie(_listensock_ptr->Fd());
         _listensock_ptr->Bind(_port);
         _listensock_ptr->Listen();
        lg(Info, "create listen socket success: %d", _listensock_ptr->Fd());
         AddConnection(_listensock_ptr->Fd(),
                      EVENT_IN, std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);

    }
    void Accepter(std::weak_ptr<Connection> conn)//// 链接管理器
    {
        auto connection=conn.lock();
        while(true)
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            int sock=::accept(connection->SockFd(),(struct sockaddr*)&peer,&len);
            if(sock>0)
            {
                uint16_t clientport=ntohs(peer.sin_port);
                char ipbuf[128];
                inet_ntop(AF_INET,&peer.sin_addr.s_addr,ipbuf,sizeof(ipbuf));
                 lg(Debug, "get a new client, get info-> [%s:%d], sockfd : %d", ipbuf, clientport, sock);
                 SetNonBlockOrDie(sock);
                  // listensock只需要设置_recv_cb, 而其他sock，读，写，异常
                AddConnection(sock, EVENT_IN,
                              std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                              std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                              std::bind(&TcpServer::Excepter, this, std::placeholders::_1),
                              ipbuf, clientport); // TODO
            }
            else
            {
                if (errno == EWOULDBLOCK)//操作可能会被阻塞
                    break;
                else if (errno == EINTR)//意味着系统调用被一个信号中断。
                    continue;
                else
                {
                    break;
                }
            }
        }
    }
    void Recver(std::weak_ptr<Connection> conn)
    {
        if(conn.expired()) return;//成员函数检查这个弱引用是否仍然有效，即它是否仍然指向一个存在的对象。如果 shared_ptr 被销毁（即没有更多的 shared_ptr 或 weak_ptr 指向它），那么 weak_ptr 会变为过期状态
        auto connection=conn.lock();
        int sock=connection->SockFd();
        while(true)
        {
            char buffer[g_buffer_size];
            memset(buffer,0,sizeof(buffer));
            ssize_t n=recv(sock,buffer,sizeof(buffer)-1,0);//// 非阻塞读取
            if(n>0)
            {
                connection->AppendInBuffer(buffer);
            }
            else if(n==0)
            {
                lg(Info, "sockfd: %d, client info %s:%d quit...", sock, connection->_ip.c_str(), connection->_port);
                 connection->_except_cb(connection);
                return;
            }
            else{
                if(errno == EWOULDBLOCK)
                {
                    break;
                }
                else if (errno == EINTR)//意味着系统调用被一个信号中断。
                    continue;
                else
                {
                    lg(Warning, "sockfd: %d, client info %s:%d recv error...", sock, connection->_ip.c_str(), connection->_port);
                    connection->_except_cb(connection);
                    return;
                }  
            }
        }
      // 数据有了，但是不一定全，1. 检测 2. 如果有完整报文，就处理
        _OnMessage(connection); // 你读到的sock所有的数据connection
    }
    void Sender(std::weak_ptr<Connection> conn)
    {
         if(conn.expired()) return;
         auto connection=conn.lock();
        auto &outbuffer = connection->OutBuffer();
        while(true)
        {
            ssize_t n=send(connection->SockFd(),outbuffer.c_str(),outbuffer.size(),0);
             if(n > 0)
            {
                outbuffer.erase(0, n);
                if(outbuffer.empty()) break;
            }
            else if(n == 0)
            {
                return;
            }
            else
            {
                if(errno == EWOULDBLOCK) break;
                else if(errno == EINTR) continue;
                else{
                    lg(Warning, "sockfd: %d, client info %s:%d send error...", connection->SockFd(), connection->_ip.c_str(), connection->_port);
                    connection->_except_cb(connection);
                    return;
                }
            }
        }
         if(!outbuffer.empty())
        {
            // 开启对写事件的关心
            EnableEvent(connection->SockFd(), true, true);
        }
        else
        {
            // 关闭对写事件的关心
            EnableEvent(connection->SockFd(), true, false);
        }
    }
     void EnableEvent(int sock, bool readable, bool writeable)
    {
        uint32_t events = 0;
        events |= ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0) | EPOLLET);
        _epoller_ptr->EpllerUpdate(EPOLL_CTL_MOD, sock, events);
    }
     bool IsConnectionSafe(int fd)
    {
        auto iter = _connections.find(fd);
        if (iter == _connections.end())
            return false;
        else
            return true;
    }
    void Excepter(std::weak_ptr<Connection> connection)
    {
        if(connection.expired()) return;
        auto conn = connection.lock();
        int fd = conn->SockFd();
        int fd = conn->SockFd();
        lg(Warning, "Excepter hander sockfd: %d, client info %s:%d excepter handler",
           conn->SockFd(), conn->_ip.c_str(), conn->_port);
        // 1. 移除对特定fd的关心
        // EnableEvent(connection->SockFd(), false, false);
        _epoller_ptr->EpllerUpdate(EPOLL_CTL_DEL, fd, 0);
         // 2. 关闭异常的文件描述符
        lg(Debug, "close %d done...\n", fd);
        close(fd);
         // 3. 从unordered_map中移除
        lg(Debug, "remove %d from _connections...\n", fd);
          _connections.erase(fd);
    }
     void AddConnection(int sock, uint32_t event, func_t recv_cb, func_t send_cb, except_func except_cb,
                       const std::string &ip = "0.0.0.0", uint16_t port = 0)
    {
        //1. 给sock也建立一个connection对象，将listensock添加到Connection中，同时，listensock和Connecion放入_connections
        std::shared_ptr<Connection>new_connection (new Connection(sock));
        new_connection->SetWeakPtr(shared_from_this());// shared_from_this(): 返回当前对象的shared_ptr
        new_connection->SetHandler(recv_cb, send_cb, except_cb);
        new_connection->_ip = ip;
        new_connection->_port = port;
        //2.将connection放入connections
        _connections.insert(make_pair(sock,new_connection));
        // 3. 我们添加对应的事件，除了要加到内核中，fd， event
         _epoller_ptr->EpllerUpdate(EPOLL_CTL_ADD, sock, event);
    }
     void Dispatcher(int timeout)
    {
        int n = _epoller_ptr->EpollerWait(revs, num, timeout);
        for (int i = 0; i < n; i++)
        {
            uint32_t events = revs[i].events;
            int sock = revs[i].data.fd;
            // 统一把事件异常转换成为读写问题
            // if (events & EPOLLERR)
            //     events |= (EPOLLIN | EPOLLOUT);
            // if (events & EPOLLHUP)
            //     events |= (EPOLLIN | EPOLLOUT);
            // 只需要处理EPOLLIN EPOLLOUT
            if ((events & EPOLLIN) && IsConnectionSafe(sock))
            {
                if (_connections[sock]->_recv_cb)
                    _connections[sock]->_recv_cb(_connections[sock]);
            }
            if ((events & EPOLLOUT) && IsConnectionSafe(sock))
            {
                if (_connections[sock]->_send_cb)
                    _connections[sock]->_send_cb(_connections[sock]);
            }
        }
    }
     void Loop()
    {
        _quit = false;

        // AddConnection();

        while (!_quit)
        {
            // Dispatcher(3000);
            Dispatcher(-1);
            PrintConnection();
        }

        _quit = true;
    }
     void PrintConnection()
    {
        std::cout << "_connections fd list: ";
        for (auto &connection : _connections)
        {
            std::cout << connection.second->SockFd() << ", ";
            std::cout << "inbuffer: " << connection.second->Inbuffer().c_str();
        }
        std::cout << std::endl;
    }
    ~TcpServer()
    {
    }
private:
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;
    std::shared_ptr<Epoller> _epoller_ptr;
    std::shared_ptr<Sock> _listensock_ptr;
    struct epoll_event revs[num];
    std::uint16_t _port;
    // 让上层处理信息
    func_t _OnMessage;
    bool _quit;
};